# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import os
import  time
import  hashlib
import serial
import  re
import sys
import subprocess
import  threading
import signal
import logging
def sigint_handler(signum, frame):
  global is_sigint_up
  is_sigint_up = True


signal.signal(signal.SIGINT, sigint_handler)

is_sigint_up = False

class  mqttRun():
    def __init__(self):
        self.IDLE = 0
        self.RUN    = 1
        self.state = self.IDLE
        self.MD5 = None
        self.TestMode = "lua"
        self.NowTestVer = False
        self.executeTest = None
        self.NowTestStartTimer = 0
        self.TesterPath = "/home/airm2m/AIRM2M_TEST_PUB/multiTesting/"
        self.sprd_dloader = "/home/airm2m/AIRM2M_TEST_PUB/rda_linux_download/LinuxDownloadSource/Bin/sprd_dloader/DLoader -pac recVer.pac -dev "
        self.logger = logging.getLogger('serialmanage')
        self.logger.setLevel(level=logging.INFO)
        console = logging.StreamHandler()
        formatter = logging.Formatter(fmt='%(asctime)s.%(msecs)03d line:%(lineno)d %(levelname)s %(message)s', datefmt='%Y-%m-%d %X')
        console.setFormatter(formatter)
        console.setLevel(logging.INFO)
        self.logger.addHandler(console)
        pass

    def getmd5(self,file):
        m = hashlib.md5()
        with open(file,'rb') as f:
            for line in f:
                m.update(line)
        md5code = m.hexdigest()
        self.logger.info(md5code)
        return md5code
    def set_mode_download(self,dev):
        ios = serial.Serial(dev, baudrate=115200, xonxoff=0, timeout=0)
        try:
            self.send_at(ios,"AT*DOWNLOAD=1")
        except Exception as e:
            self.logger.warning(e)
        ios.close()

    def FindNewerFile(self,path,key):
        dict = []
        for root, dirs, files in os.walk(path):
            for file in dirs:
                full_path = os.path.join(root, file)
                tempMatch = re.match("(.*)_86.*_(.*)", full_path)
                if tempMatch:
                    nowTime = time.mktime(time.strptime("2020:%s" % tempMatch.group(2), "%Y:%m:%d:%H:%M:%S"))
                    if(nowTime  > self.NowTestStartTimer):
                        if os.path.exists(full_path+"//%s"%key):
                            dict.append(full_path+"//%s"%key)
        if  len(dict) != 0:
            return  dict
        else:
            return  False

    def get_log_size(self,path):
        totalSize = 0
        key =  False
        if self.TestMode == "at" :
            key = "log_"
        elif self.TestMode == "lua" :
            key = "stdout"
        if key :
            for root, dirs, files in os.walk(path):
                for file in files:
                    full_path = os.path.join(root, file)
                    if full_path.find(key) != -1:
                        totalSize =  totalSize + os.path.getsize(full_path)
        return  totalSize

        pass

    def checkFailAndSend(self,pub):
        self.logger.info("checkFailAndSend %s"%pub )
        totalSize =  0
        key = False
        if pub.find("lua") != -1:
            key = "stdout"
        elif  pub.find("at") != -1:
            key = "at_failed"
        if  key :
            res = self.FindNewerFile(self.TesterPath + "/log", key )
            if res:
                for i in range(0,len(res)):
                    self.logger.info("checkFailAndSend %s"%(res[i]))
                    data = ""
                    if res:
                        hd = open(res[i], "rb")
                        data = hd.read()
                        hd.close()
                        totalSize = self.get_log_size(os.path.dirname(res[i]))
                    self.on_publish(pub,res[i] + "_split#%d_split#%s"%(totalSize,data),1)
                    time.sleep(5)

    def on_message_come(self,lient, userdata, msg):
        self.logger.info("on_message_come topic: %s"%msg.topic)
        if msg.topic == "airm2m/UpgradeAndTest%s"%self.TestMode :
            try:
                if self.state == self.IDLE :
                    self.state = self.RUN
                    self.logger.info("lens %d",len(msg.payload))
                    data = msg.payload
                    hd = open("recVer.pac","wb")
                    hd.write(data)
                    hd.close()
                    self.NowTestStartTimer =time.time()
                    md5 = self.getmd5("recVer.pac")
                    self.logger.info("%s %s"%(md5,self.MD5))
                    if str(md5) != str(self.MD5):
                        self.logger.info("md5 err")
                        self.on_publish("airm2m/UpgradeAndTestCnf%s"%self.TestMode, "MD5校验不对", 1)
                        self.executeTest = None
                        return
                    else:
                        self.logger.info("ok")
                        atlist = self.execute_command("get_AT_list")
                        if atlist and len(atlist) > 0:
                            for i in atlist:
                                self.set_mode_download(i)
                        time.sleep(2)
                        downlodList = self.execute_command("get_download_list")
                        testFlag = False
                        if downlodList and len(downlodList) >0:
                            for i in downlodList:
                                for j in range(0,3):
                                    testFlag =  self.execute_command("download_mode", dev=i)
                                    if testFlag :
                                        break
                        if testFlag :
                            self.startTest(self.TestMode)
                        else:
                            Exception("download err")
                    self.executeTest = None
                    self.on_publish("airm2m/UpgradeAndTestCnf%s"%self.TestMode,"烧录成功,开始测试",1)
                else:
                    self.on_publish("airm2m/UpgradeAndTestCnf%s"%self.TestMode, "测试服务器不处于IDLE 状态", 1)
            except Exception  as e:
                self.on_publish("airm2m/UpgradeAndTestCnf%s"%self.TestMode, str(e), 1)
                self.state = self.IDLE
        elif msg.topic == "airm2m/UpgradeAndTestMD5%s"%self.TestMode  :
            self.MD5 = str(msg.payload,encoding = "gbk")
            self.logger.info("get net md5 %s"%(self.MD5))
        elif msg.topic == "airm2m/testTesultEndReq%s"%self.TestMode  :
            if self.state != self.IDLE:
                self.checkFailAndSend("airm2m/testTesultEndCnf%s"%self.TestMode)
                if self.executeTest:
                    self.executeTest.kill()
                self.executeTest = None
                self.state= self.IDLE
        elif msg.topic == "airm2m/testcirculateReq%s"%self.TestMode  :
            if self.state != self.IDLE:
                self.checkFailAndSend("airm2m/testcirculateCnf%s"%self.TestMode)
        elif msg.topic == "airm2m/StopReq%s"%self.TestMode:
            if self.state != self.IDLE:
                if self.executeTest:
                    self.executeTest.stop_thread()
                self.state = self.IDLE
                self.on_publish("airm2m/StopCnf%s"%self.TestMode, "0", 1)

            pass

        # print(msg.topic + " " + ":" + str(msg.payload))

    def send_at(self, h_serial, at, back_data=False, timeout=20):
        start = time.clock()
        timeout = timeout
        h_serial.flushInput()
        h_serial.flushOutput()
        read = ""
        h_serial.write((at + "\r\n").encode("gbk"))
        self.logger.info("send at:" + str(at) + "\r\n")
        while True:
            read = read + str(h_serial.read(), encoding='gbk')
            if read.find("OK") != -1:
                if back_data:
                    if read.find(back_data) != -1:
                        return True
                    else:
                        return False
                else:
                    return read

            if time.clock() > timeout + start:
                raise Exception("time out")

    def runTest(self,type):
        self.logger.info("runTest %s"%type)

        nowPath = os.getcwd()
        os.chdir(self.TesterPath)
        os.system("git pull")
        os.system("sudo python3 main.py > log.txt")
        os.chdir(nowPath)

    def startTest(self,type):


        # if type == "AT":
        self.executeTest = threading.Thread(target=self.runTest, args=(type,))
        self.executeTest.start()


        self.logger.info("%s startTesting"%self.TestMode)





    def execute_command(self, type ,dev = False ):
        self.logger.info('start executing cmd...')
        portList = []
        if type == "get_AT_list":
            cmd = "./diag  1782 4e00 3 0"
        elif type == "get_download_list":
            cmd = "./diag  0525 a4a7  0 1"
        elif type == "download_mode":
            cmd = self.sprd_dloader + " %s -reset 1"%(dev)
        self.logger.info("execute_command: %s"%cmd)
        self.executecommand = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,
                                               stdout=subprocess.PIPE)
        line = self.executecommand.stdout.readline()
        while line:
            line = self.executecommand.stdout.readline()
            if line:
                try:
                    line = str(line, encoding="gbk")
                    self.logger.info(line)
                    if type == "get_AT_list":
                        gb = re.match("AT (.*)", line)
                        if gb:
                            self.logger.info("find AT port %s"%gb.group(1))
                            portList.append("/dev/%s" % gb.group(1))
                    elif type == "get_download_list":
                        gb = re.match("Download (.*)", line)
                        if gb:
                            self.logger.info("find Download port %s" % gb.group(1))
                            portList.append("/dev/%s"%gb.group(1))
                    elif type == "download_mode":
                        if line.find("download success") != -1:
                            self.logger.info("%s Download sucess" % dev)
                            self.executecommand.kill()
                            return  True

                except Exception as e:
                    line = str(line)


        self.executecommand.kill()
        self.executecommand = False
        if type == "get_AT_list" or type == "get_download_list":
            if len(portList) > 0:
                return  portList
            else:
                return  False
        else:
            return False



    def on_subscribe(self):
        self.mqttClient.subscribe("airm2m/UpgradeAndTest%s"%self.TestMode, 1)
        self.mqttClient.subscribe("airm2m/UpgradeAndTestMD5%s"%self.TestMode, 1)
        self.mqttClient.subscribe("airm2m/UpgradeAndTesVer%s"%self.TestMode, 1)
        self.mqttClient.subscribe("airm2m/testTesultEndReq%s"%self.TestMode, 1)
        self.mqttClient.subscribe("airm2m/testcirculateReq%s"%self.TestMode, 1)
        self.mqttClient.subscribe("airm2m/StopReq%s"%self.TestMode, 1)

        self.mqttClient.on_message = self.on_message_come



    def startMqtt(self):
        MQTTHOST = "192.168.39.233"
        MQTTPORT = 1883
        self.mqttClient = mqtt.Client()
        self.mqttClient.connect(MQTTHOST, MQTTPORT, 60)
        self.mqttClient.loop_start()
        pass

    def on_publish(self,topic,mes,qos):
        self.mqttClient.publish(topic, mes, qos)

        pass

    def run(self):
        self.logger.info("start %s client"%self.TestMode)
        self.startMqtt()
        self.on_subscribe()
        while(True):
            global is_sigint_up
            if is_sigint_up:
                self.logger.info("CTRL+C lj")
                if self.executeTest :
                    self.logger.info("KILL  executeTest")
                    self.executeTest.kill()
                is_sigint_up = False
                sys.exit()

            time.sleep(2)



if __name__ == '__main__':
    handle = mqttRun()
    handle.run()

